package rasterization;

import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.util.ArrayList;
import java.util.List;

import javax.swing.JFrame;

import raytracing.Camera;
import raytracing.Ray;
import scene.Scene;
import scene.shape.geometry.Triangle;
import util.CgPanel;
import util.Line3D;
import util.Matrix4f;
import util.parsing.SceneBuilder;

public class RasterizerDemo implements MouseListener, MouseMotionListener, KeyListener, FocusListener{
	
	private CgPanel panel;
	private Rasterizer rasterizer;
	
	private List<Integer> keysDown;
	
	List<Line3D> lines;
	List<Triangle> triangles;
	
	Camera camera;
	
	Matrix4f mvporthp;
	
	private Scene scene;
	
	private int oldX,oldY;
	
	List<Ray> rays = new ArrayList<Ray>();
	
	public static void main(String[] args) {
		new RasterizerDemo();
	}

	public RasterizerDemo(){
		try {
			SceneBuilder sceneBuilder = new SceneBuilder();
			scene = sceneBuilder.loadScene("var/XML/example.sdl");
		}
		catch (Exception e) {
			e.printStackTrace();
		}
		panel = new CgPanel();
		JFrame frame = new JFrame();
		frame.addWindowListener(new WindowAdapter(){
			  	public void windowClosing(WindowEvent we){
			  		System.exit(0);
			  	}
			  });
		frame.addMouseListener(this);
		frame.addMouseMotionListener(this);
		frame.addKeyListener(this);
		frame.addFocusListener(this);
		frame.getContentPane().add(panel);
		frame.setSize(512,512);
		frame.setVisible(true);
		rasterizer = new Rasterizer(panel, false);
		this.keysDown = new ArrayList<Integer>();
	}
	
	public void drawLines(){
		float starttime = System.currentTimeMillis(), endTime;
		rasterizer.renderScene();
		endTime = System.currentTimeMillis();
		System.out.println("Finished drawing in " + (endTime - starttime) + "ms");
	}
	
	public void keyPressed(KeyEvent e) {
		if((e.getKeyCode() == KeyEvent.VK_Q ||
				e.getKeyCode() == KeyEvent.VK_D ||
				e.getKeyCode() == KeyEvent.VK_Z ||
				e.getKeyCode() == KeyEvent.VK_S ||
				e.getKeyCode() == KeyEvent.VK_SPACE ||
				e.getKeyCode() == KeyEvent.VK_X) && !keysDown.contains(e.getKeyCode())){
			keysDown.add(e.getKeyCode());
		}
		if(keysDown.size() >= 1){
			if(keysDown.contains(KeyEvent.VK_Q)){
				scene.getCurrentCamera().setEye(scene.getCurrentCamera().getEye().add(scene.getCurrentCamera().getU().scale(-0.1F)));
				scene.getCurrentCamera().setLookat(scene.getCurrentCamera().getLookat().add(scene.getCurrentCamera().getU().scale(-0.1F)));
			}
			if(keysDown.contains(KeyEvent.VK_D)){
				scene.getCurrentCamera().setEye(scene.getCurrentCamera().getEye().add(scene.getCurrentCamera().getU().scale(0.1F)));
				scene.getCurrentCamera().setLookat(scene.getCurrentCamera().getLookat().add(scene.getCurrentCamera().getU().scale(0.1F)));
			}if(keysDown.contains(KeyEvent.VK_Z)){
				scene.getCurrentCamera().setEye(scene.getCurrentCamera().getEye().add(scene.getCurrentCamera().getW().scale(-0.1F)));
				scene.getCurrentCamera().setLookat(scene.getCurrentCamera().getLookat().add(scene.getCurrentCamera().getW().scale(-0.1F)));
			}
			if(keysDown.contains(KeyEvent.VK_S)){
				scene.getCurrentCamera().setEye(scene.getCurrentCamera().getEye().add(scene.getCurrentCamera().getW().scale(0.1F)));
				scene.getCurrentCamera().setLookat(scene.getCurrentCamera().getLookat().add(scene.getCurrentCamera().getW().scale(0.1F)));
			}
			if(keysDown.contains(KeyEvent.VK_SPACE)){
				scene.getCurrentCamera().setEye(scene.getCurrentCamera().getEye().add(scene.getCurrentCamera().getV().scale(0.1F)));
				scene.getCurrentCamera().setLookat(scene.getCurrentCamera().getLookat().add(scene.getCurrentCamera().getV().scale(0.1F)));
			}
			if(keysDown.contains(KeyEvent.VK_X)){
				scene.getCurrentCamera().setEye(scene.getCurrentCamera().getEye().add(scene.getCurrentCamera().getV().scale(-0.1F)));
				scene.getCurrentCamera().setLookat(scene.getCurrentCamera().getLookat().add(scene.getCurrentCamera().getV().scale(-0.1F)));
			}
			drawLines();
		}
	}

	public void mouseClicked(MouseEvent e) {
		drawLines();
	}
	public void mouseEntered(MouseEvent e) {}
	public void mouseExited(MouseEvent e) {}
	public void mousePressed(MouseEvent e) {}
	public void mouseReleased(MouseEvent e) {oldX = 0; oldY = 0;}

	@Override
	public void keyReleased(KeyEvent e) {
		keysDown.remove(new Integer(e.getKeyCode()));
	}
	@Override
	public void keyTyped(KeyEvent arg0) {}

	@Override
	public void mouseDragged(MouseEvent e) {
		if(e.getID() == MouseEvent.MOUSE_DRAGGED){
			if(oldX != 0 && oldY != 0){
				int dx = oldX - e.getX(), dy = oldY - e.getY();
				scene.getCurrentCamera().setLookat(scene.getCurrentCamera().getLookat().add(scene.getCurrentCamera().getV().scale(dy * 0.01f)));
				scene.getCurrentCamera().setLookat(scene.getCurrentCamera().getLookat().add(scene.getCurrentCamera().getU().scale(dx * -0.01f)));
			}
			oldX = e.getX();
			oldY = e.getY();
			drawLines();
		}
	}

	@Override
	public void mouseMoved(MouseEvent arg0) {}

	@Override
	public void focusGained(FocusEvent arg0) {}

	@Override
	public void focusLost(FocusEvent arg0) {
		keysDown.clear();
	}

}
